import os
import json
import requests
import logging
from datetime import datetime, timedelta
import re
from flask import Flask, request, jsonify
from flask_cors import CORS


# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    handlers=[logging.FileHandler("deepseek_weather.log"), logging.StreamHandler()]
)
logger = logging.getLogger("deepseek_weather")
# 初始化数据库


app = Flask(__name__)
CORS(app)  # 允许跨域请求

# 配置
WEATHER_API_BASE_URL = os.getenv("WEATHER_API_URL", "http://localhost:5000")
# WEATHER_API_BASE_URL = os.getenv("WEATHER_API_URL", "http://172.16.52.27:5001")
DEEPSEEK_API_KEY = os.getenv("DEEPSEEK_API_KEY", "sk-b17f3da985ee41c59422963c0b3a2e30")
DEEPSEEK_API_URL = os.getenv("DEEPSEEK_API_URL", "https://api.deepseek.com/v1/chat/completions")

# 城市代码映射表 (中文名称到API使用的代码)
CITY_CODES = {
    "北京": "beijing",
    "上海": "shanghai",
    "广州": "guangzhou",
    "深圳": "shenzhen",
    "成都": "chengdu",
    "杭州": "hangzhou",
    "南京": "nanjing",
    "武汉": "wuhan",
    "西安": "xian",
    "重庆": "chongqing",
    "天津": "tianjin",
    "苏州": "suzhou",
    "青岛": "qingdao"
}

# 反向映射 (代码到中文名称)
CITY_NAMES = {code: name for name, code in CITY_CODES.items()}


def call_weather_api(endpoint, params=None):
    """调用天气API"""
    if params is None:
        params = {}

    try:
        url = f"{WEATHER_API_BASE_URL}{endpoint}"
        logger.info(f"调用天气API: {url}, 参数: {params}")

        response = requests.get(url, params=params, timeout=10)

        if response.status_code == 200:
            data = response.json()
            logger.info(f"天气API响应成功: {endpoint}")
            return data
        else:
            logger.error(f"天气API错误: HTTP {response.status_code}, {response.text}")
            return {
                "status": "error",
                "message": f"天气API返回错误: HTTP {response.status_code}"
            }
    except Exception as e:
        logger.error(f"调用天气API异常: {str(e)}")
        return {
            "status": "error",
            "message": f"调用天气API时出错: {str(e)}"
        }


def call_deepseek_api(messages):
    """调用DeepSeek大模型API"""
    try:
        headers = {
            "Content-Type": "application/json",
            "Authorization": f"Bearer {DEEPSEEK_API_KEY}"
        }

        payload = {
            "model": "deepseek-chat",
            "messages": messages,
            "temperature": 0.7,
            "max_tokens": 800
        }

        logger.info(f"调用DeepSeek API")
        response = requests.post(
            DEEPSEEK_API_URL,
            headers=headers,
            json=payload,
            timeout=30
        )

        if response.status_code == 200:
            result = response.json()
            if "choices" in result and len(result["choices"]) > 0:
                content = result["choices"][0]["message"]["content"]
                logger.info(f"DeepSeek API响应成功")
                return {
                    "status": "success",
                    "content": content
                }
            else:
                logger.error(f"DeepSeek API响应格式错误: {result}")
                return {
                    "status": "error",
                    "message": "无法解析DeepSeek的响应"
                }
        else:
            logger.error(f"DeepSeek API错误: HTTP {response.status_code}, {response.text}")
            return {
                "status": "error",
                "message": f"DeepSeek API返回错误: HTTP {response.status_code}"
            }
    except Exception as e:
        logger.error(f"调用DeepSeek API异常: {str(e)}")
        return {
            "status": "error",
            "message": f"调用DeepSeek API时出错: {str(e)}"
        }


def parse_weather_query(query):
    """使用DeepSeek分析用户的天气查询"""
    messages = [
        {"role": "system", "content": """你是一个专门解析天气查询的助手。  
请分析用户的查询，提取以下信息：  
1. 查询的城市  
2. 查询的时间类型（当前天气、特定日期、特定月份或时间范围）  
3. 具体的日期或月份（如果有）  

只返回JSON格式的结果，不要有任何额外的文字。  
格式如下：  
{  
  "city": "城市代码",  
  "query_type": "current|date|month|range",  
  "date": "YYYY-MM-DD", (仅当query_type为date时)  
  "month": "YYYYMM", (仅当query_type为month时)  
  "start_date": "YYYY-MM-DD", (仅当query_type为range时)  
  "end_date": "YYYY-MM-DD" (仅当query_type为range时)  
}  

城市代码对照表：  
北京: beijing  
上海: shanghai  
广州: guangzhou  
深圳: shenzhen  
成都: chengdu  
杭州: hangzhou  
南京: nanjing  
武汉: wuhan  
西安: xian  
重庆: chongqing  
天津: tianjin  
苏州: suzhou  
青岛: qingdao"""},
        {"role": "user", "content": query}
    ]

    result = call_deepseek_api(messages)

    if result["status"] == "success":
        try:
            # 尝试从响应中提取JSON
            content = result["content"]
            json_match = re.search(r'\{.*\}', content, re.DOTALL)
            if json_match:
                json_str = json_match.group(0)
                query_info = json.loads(json_str)
                logger.info(f"成功解析查询信息: {query_info}")
                return query_info
            else:
                logger.error(f"无法从DeepSeek响应中提取JSON: {content}")
                return fallback_parse_query(query)
        except Exception as e:
            logger.error(f"解析DeepSeek响应异常: {str(e)}")
            return fallback_parse_query(query)
    else:
        logger.error(f"调用DeepSeek解析查询失败: {result.get('message')}")
        return fallback_parse_query(query)


def fallback_parse_query(query):
    """当DeepSeek API不可用时，使用简单规则解析查询"""
    logger.info("使用备用方法解析查询")

    # 默认值
    query_info = {
        "city": "beijing",  # 默认城市
        "query_type": "current"  # 默认查询当前天气
    }

    # 尝试识别城市
    for name, code in CITY_CODES.items():
        if name in query:
            query_info["city"] = code
            break

            # 尝试识别日期类型
    if "月" in query and "天" not in query and "日" not in query:
        # 可能是月度查询
        query_info["query_type"] = "month"

        # 尝试提取年月
        month_match = re.search(r'(\d{4})年(\d{1,2})月', query)
        if month_match:
            year = month_match.group(1)
            month = month_match.group(2).zfill(2)
            query_info["month"] = f"{year}{month}"
        else:
            # 如果没有明确指定年月，使用当前月
            current_month = datetime.now().strftime("%Y%m")
            query_info["month"] = current_month

    elif "历史" in query or ("从" in query and "到" in query):
        # 可能是日期范围查询
        query_info["query_type"] = "range"

        # 默认为最近30天
        end_date = datetime.now()
        start_date = end_date - timedelta(days=30)

        query_info["start_date"] = start_date.strftime("%Y-%m-%d")
        query_info["end_date"] = end_date.strftime("%Y-%m-%d")

    elif any(word in query for word in ["明天", "后天", "昨天", "前天"]) or re.search(r'\d+日', query):
        # 可能是特定日期查询
        query_info["query_type"] = "date"

        today = datetime.now()

        if "明天" in query:
            query_date = today + timedelta(days=1)
        elif "后天" in query:
            query_date = today + timedelta(days=2)
        elif "昨天" in query:
            query_date = today - timedelta(days=1)
        elif "前天" in query:
            query_date = today - timedelta(days=2)
        else:
            # 默认今天
            query_date = today

        query_info["date"] = query_date.strftime("%Y-%m-%d")

    logger.info(f"备用方法解析结果: {query_info}")
    return query_info


def generate_weather_response(weather_data, query_info):
    """使用DeepSeek生成自然语言的天气响应"""
    # 准备天气数据的JSON字符串
    weather_json = json.dumps(weather_data, ensure_ascii=False, indent=2)

    # 获取城市的中文名称
    city_code = query_info.get("city", "beijing")
    city_name = CITY_NAMES.get(city_code, city_code)

    # 构建提示词
    messages = [
        {"role": "system", "content": f"""你是一个专业的天气助手，请将API返回的天气数据转换为自然、友好的回复。  
当前查询的是{city_name}的天气信息。根据提供的天气数据JSON和查询类型，生成一个简洁但信息丰富的回复。  
回复应该是自然流畅的对话，包含所有重要的天气信息，但不要机械地罗列数据。  

回复风格指南:  
1. 使用自然的语言描述天气情况  
2. 提及用户查询的城市和时间范围  
3. 对特殊天气提供简单建议（如高温建议多喝水，雨天建议带伞等）  
4. 回复保持友好、有帮助的语气  
5. 如果是历史数据，可以提炼出趋势或特点  

请根据不同的查询类型(当前天气、特定日期、月度天气或日期范围)组织合适的回复结构。"""},
        {"role": "user", "content": f"查询类型: {query_info['query_type']}\n\n天气数据: {weather_json}"}
    ]

    result = call_deepseek_api(messages)

    if result["status"] == "success":
        logger.info("成功生成天气响应")
        return result["content"]
    else:
        logger.warning(f"调用DeepSeek生成响应失败，使用备用方法")
        return fallback_format_response(weather_data, query_info)


def fallback_format_response(weather_data, query_info):
    """当DeepSeek API不可用时，使用简单格式化生成响应"""
    query_type = query_info.get("query_type")
    city_code = query_info.get("city", "beijing")
    city_name = CITY_NAMES.get(city_code, city_code)

    if weather_data.get("status") != "success":
        return f"抱歉，获取{city_name}的天气信息失败: {weather_data.get('message', '未知错误')}"

    if query_type == "current":
        if "weather" in weather_data:
            weather = weather_data["weather"]
            return f"{city_name}当前天气：{weather.get('date', '')}，气温{weather.get('low_temp', '')}至{weather.get('high_temp', '')}，{weather.get('weather', '')}，{weather.get('wind_direction', '')} {weather.get('wind_force', '')}。"
        else:
            return f"抱歉，未能获取{city_name}的当前天气信息。"

    elif query_type == "date":
        if "weather" in weather_data:
            weather = weather_data["weather"]
            date = query_info.get("date", "")
            return f"{city_name}{date}的天气：气温{weather.get('low_temp', '')}至{weather.get('high_temp', '')}，{weather.get('weather', '')}，{weather.get('wind_direction', '')} {weather.get('wind_force', '')}。"
        else:
            date = query_info.get("date", "")
            return f"抱歉，未能获取{city_name}{date}的天气信息。"

    elif query_type == "month":
        if "data" in weather_data and len(weather_data["data"]) > 0:
            data = weather_data["data"]
            month = query_info.get("month", "")
            formatted_month = f"{month[:4]}年{month[4:6]}月" if len(month) == 6 else month
            response = f"{city_name}{formatted_month}的天气概况（共{len(data)}天）：\n"

            # 显示前5天数据
            for i, day in enumerate(data[:5]):
                response += f"{day.get('date', '')}: 气温{day.get('low_temp', '')}至{day.get('high_temp', '')}，{day.get('weather', '')}，{day.get('wind_direction', '')} {day.get('wind_force', '')}\n"

            if len(data) > 5:
                response += "...(更多数据省略)\n"

            return response
        else:
            month = query_info.get("month", "")
            formatted_month = f"{month[:4]}年{month[4:6]}月" if len(month) == 6 else month
            return f"抱歉，未能获取{city_name}{formatted_month}的天气信息。"

    elif query_type == "range":
        if "data" in weather_data and len(weather_data["data"]) > 0:
            data = weather_data["data"]
            start_date = query_info.get("start_date", "")
            end_date = query_info.get("end_date", "")
            response = f"{city_name}从{start_date}到{end_date}的天气记录（共{len(data)}天）：\n"

            # 显示前5天数据
            for i, day in enumerate(data[:5]):
                response += f"{day.get('date', '')}: 气温{day.get('low_temp', '')}至{day.get('high_temp', '')}，{day.get('weather', '')}，{day.get('wind_direction', '')} {day.get('wind_force', '')}\n"

            if len(data) > 5:
                response += "...(更多数据省略)\n"

            return response
        else:
            start_date = query_info.get("start_date", "")
            end_date = query_info.get("end_date", "")
            return f"抱歉，未能获取{city_name}从{start_date}到{end_date}的天气信息。"

    return f"抱歉，无法处理您的查询。"


def process_weather_query(query):
    """处理天气查询的主函数"""
    logger.info(f"收到天气查询: {query}")

    # 1. 解析查询，确定意图和参数
    query_info = parse_weather_query(query)

    if not query_info:
        return {
            "status": "error",
            "message": "无法理解您的查询，请尝试更明确的表述。"
        }

        # 2. 根据查询类型调用相应的API
    weather_data = {}
    city = query_info.get("city")

    try:
        if query_info["query_type"] == "current":
            # 获取当前天气
            weather_data = call_weather_api("/api/weather/current", {"city": city})

        elif query_info["query_type"] == "date":
            # 获取特定日期的天气
            date = query_info.get("date")
            weather_data = call_weather_api("/api/weather", {"city": city, "date": date})

        elif query_info["query_type"] == "month":
            # 获取月度天气
            month = query_info.get("month")
            weather_data = call_weather_api("/api/weather/month", {"city": city, "month": month})

        elif query_info["query_type"] == "range":
            # 获取日期范围的天气
            start_date = query_info.get("start_date")
            end_date = query_info.get("end_date")
            weather_data = call_weather_api("/api/weather/history", {
                "city": city,
                "start_date": start_date,
                "end_date": end_date
            })

            # 3. 根据API响应生成自然语言回复
        if weather_data.get("status") == "success":
            response = generate_weather_response(weather_data, query_info)
        else:
            error_msg = weather_data.get("message", "未知错误")
            response = f"抱歉，无法获取天气信息: {error_msg}"

        return {
            "status": "success",
            "query_info": query_info,
            "response": response
        }

    except Exception as e:
        logger.error(f"处理天气查询异常: {str(e)}")
        return {
            "status": "error",
            "message": f"处理查询时出错: {str(e)}"
        }


@app.route('/api/query', methods=['POST'])
def handle_query():
    """处理用户的自然语言天气查询"""
    if not request.json or 'query' not in request.json:
        return jsonify({
            "status": "error",
            "message": "请求必须包含'query'字段"
        }), 400

    query = request.json['query']
    result = process_weather_query(query)

    return jsonify(result)


@app.route('/api/cities', methods=['GET'])
def get_cities():
    """获取可用的城市列表"""
    try:
        # 转发请求到天气API
        result = call_weather_api("/api/cities")
        return jsonify(result)
    except Exception as e:
        logger.error(f"获取城市列表异常: {str(e)}")

        # 如果API不可用，返回预定义的城市列表
        fallback_cities = [
            {"id": i + 1, "name": name, "code": code}
            for i, (name, code) in enumerate(CITY_CODES.items())
        ]

        return jsonify({
            "status": "success",
            "count": len(fallback_cities),
            "cities": fallback_cities,
            "note": "使用预定义城市列表，原因：" + str(e)
        })


@app.route('/api/test', methods=['GET'])
def test_connection():
    """测试与天气API的连接"""
    try:
        health_check = call_weather_api("/api/weather", {"city": "beijing"})
        deepseek_status = "可用" if DEEPSEEK_API_KEY != "sk-b17f3da985ee41c59422963c0b3a2e30" else "未配置"

        return jsonify({
            "status": "success",
            "weather_api_status": "可用" if health_check.get("status") == "success" else "不可用",
            "weather_api_url": WEATHER_API_BASE_URL,
            "deepseek_api_status": deepseek_status,
            "time": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        })
    except Exception as e:
        return jsonify({
            "status": "error",
            "message": f"测试连接失败: {str(e)}",
            "weather_api_url": WEATHER_API_BASE_URL,
            "time": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        })


if __name__ == '__main__':
    logger.info("启动DeepSeek天气查询服务")

    # 启动API服务
    app.run(debug=True, host='0.0.0.0', port=5001)